package net.goutalk.glcs.config;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import net.goutalk.glcs.common.handler.EasyExcelLocalDateTimeConverter;
import net.goutalk.glcs.common.utils.LocalDateTimeUtil;
import lombok.SneakyThrows;
import oracle.sql.INTERVALDS;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author: tanyujie
 * @Date: 2022/8/2 16:54
 */
@Configuration
public class JacksonConfig {

    @Value("${spring.jackson.date-format}")
    private String pattern;

    /**
     * 默认设置所有long类型 序列化返回前端 全变成string
     *           所有LocalDatetime 序列号返回前端  全部格式化
     * @return
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            builder.serializerByType(Long.class, ToStringSerializer.instance);
            builder.serializerByType(Long.TYPE, ToStringSerializer.instance);
            builder.serializerByType(BigDecimal.class, ToStringSerializer.instance);
            builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
            builder.serializerByType(INTERVALDS.class, intervalDSSerializer());
            builder.deserializerByType(LocalDateTime.class, localDateTimeDeserializer());
            builder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
            builder.visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
            builder.visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
            builder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE);
        };
    }

    /**
     * localDatetime格式化
     * @return
     */
    @Bean
    public LocalDateTimeSerializer localDateTimeSerializer(){
        return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * oracle字段类型INTERVALDS格式化
     * @return
     */
    @Bean
    public JsonSerializer<INTERVALDS> intervalDSSerializer() {
        return new JsonSerializer<INTERVALDS>() {
            @Override
            public void serialize(INTERVALDS time, JsonGenerator g, SerializerProvider provider) throws IOException {
                g.writeString(LocalDateTimeUtil.convertIntervalToLocalTime(time).format(DateTimeFormatter.ISO_LOCAL_TIME));
            }
        };
    }

    /**
     * localDatetime格式化
     * @return
     */
    @Bean
    public JsonDeserializer<LocalDateTime> localDateTimeDeserializer(){
        final String pattern = this.pattern;
        return new JsonDeserializer<LocalDateTime>(){
            @SneakyThrows
            @Override
            public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
                String value = p.getText();
                if (StrUtil.isEmpty(value)) {
                    return null;
                }
                Class<?> aClass = p.getCurrentValue().getClass();
                Field field = ReflectUtil.getField(aClass, p.getCurrentName());
                String format = pattern;
                JsonFormat annotation = field.getAnnotation(JsonFormat.class);
                if (annotation != null) {
                    format = StringUtils.defaultIfEmpty(annotation.pattern(), pattern);
                }
                return LocalDateTimeUtil.parseDate(value, format);
            }
        };
    }

    @Bean
    public Converter<String, LocalDateTime> stringToLocalDateTimeConverter() {
        /** EasyExcel时间格式配置 */
        EasyExcelLocalDateTimeConverter converter = new EasyExcelLocalDateTimeConverter();
        DefaultConverterLoader.loadDefaultReadConverter().put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
        DefaultConverterLoader.loadDefaultWriteConverter().put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
        DefaultConverterLoader.loadDefaultWriteConverter().put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
        /***/
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String value) {
                return LocalDateTimeUtil.parseDateByLength(value);
            }
        };
    }

    @Bean
    public Converter<String, LocalTime> stringToLocalTimeConverter() {
        return new Converter<String, LocalTime>(){

            @Override
            public LocalTime convert(String value) {
                if (StrUtil.isNotBlank(value)) {
                    return LocalTime.parse(value);
                }
                return null;
            }
        };
    }
}
